package com.wlyuan.index.application.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wlyuan.core.domain.valueobj.WaybillId;
import com.wlyuan.core.exception.ValueError;
import com.wlyuan.index.api.IWaybillIndexService;
import com.wlyuan.index.api.dto.QuotationIndexDTO;
import com.wlyuan.index.api.dto.waybill.*;
import com.wlyuan.index.api.vo.WaybillIndexScrollVO;
import com.wlyuan.index.api.vo.WaybillIndexSumVO;
import com.wlyuan.index.api.vo.WaybillIndexVO;
import com.wlyuan.index.application.translator.WaybillIndexTranslator;
import com.wlyuan.index.domain.index.repository.WaybillIndexRepository;
import com.wlyuan.index.domain.index.service.WaybillIndexDiffService;
import com.wlyuan.index.domain.index.service.WaybillIndexRenewService;
import com.wlyuan.index.domain.index.service.WaybillIndexSearchService;
import com.wlyuan.index.domain.index.service.reindex.WaybillReindexService;
import com.wlyuan.index.domain.source.factory.SourceFactory;
import com.wlyuan.index.domain.source.utils.SourceUtils;
import com.wlyuan.index.infrastructure.config.WaybillIndexProperties;
import com.wlyuan.index.infrastructure.converter.WaybillIndexConverter;
import com.wlyuan.tools.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author yuanjie
 */
@DubboService
@Slf4j
@RequiredArgsConstructor
public class WaybillIndexServiceImpl implements IWaybillIndexService {
    private final WaybillIndexProperties indexProperties;
    private final WaybillIndexRepository indexRepository;
    private final WaybillIndexRenewService renewService;
    private final WaybillIndexDiffService diffService;
    private final WaybillIndexSearchService searchService;
    private final WaybillReindexService reindexService;
    private final SourceFactory sourceFactory;

    @Override
    public void index(Long waybillId) {
        renewService.add(new WaybillId(waybillId));
    }

    @Override
    public void index(List<Long> waybillIds) {
        if (CollectionUtils.isEmpty(waybillIds)) {
            return;
        }
        waybillIds.forEach(this::index);
    }

    @Override
    public void index(WaybillIndexDTO waybill) {
        if (logger.isDebugEnabled()) {
            logger.debug("运单信息更新: {}", JSON.toJSON(waybill));
        }
        sourceFactory.create(waybill);
        renewService.add(new WaybillId(waybill.getWaybillId()));
    }

    @Override
    public void index(BalanceIndexDTO balance) {
        if (logger.isDebugEnabled()) {
            logger.debug("付款信息更新: {}", JSON.toJSON(balance));
        }
        sourceFactory.create(balance);
        renewService.add(new WaybillId(balance.getWaybillId()));
    }

    @Override
    public void index(QuotationIndexDTO quotation) {
        if (logger.isDebugEnabled()) {
            logger.debug("报价信息更新: {}", JSON.toJSON(quotation));
        }
        if (!SourceUtils.isWaybillQuote(quotation)) {
            logger.error("必须是运单报价: {}", quotation);
            return;
        }

        sourceFactory.create(quotation);
        renewService.add(new WaybillId(quotation.getSourceId()));
    }

    @Override
    public void index(BillIndexDTO bill) {
        if (logger.isDebugEnabled()) {
            logger.debug("账单信息更新: {}", JSON.toJSON(bill));
        }
        sourceFactory.create(bill);
        var waybillIds = bill.getWaybillIds();
        if (CollectionUtils.isEmpty(waybillIds)) {
            return;
        }
        waybillIds.forEach(waybillId -> renewService.add(new WaybillId(waybillId)));
    }

    @Override
    public void reindex(Long waybillId) {
        reindexService.reindex(new WaybillId(waybillId));
    }

    @Override
    public void reindex(WaybillReindexDTO reindex) {
        reindexService.reindex(reindex);
    }

    @Override
    public void reindexAll(List<Long> waybillIds) {
        if (CollectionUtils.isEmpty(waybillIds)) {
            return;
        }
        logger.info("重建运单索引数量: {}", waybillIds.size());
        var ids = waybillIds.stream()
                .map(WaybillId::new)
                .collect(Collectors.toList());
        reindexService.reindexAll(ids);
    }

    @Override
    public void reindexAll(WaybillReindexAllDTO reindex) {
        if (!indexProperties.isEnableReindexAll()) {
            logger.info("重建运单索引功能已禁用: {}", reindex);
            throw new ValueError("重建运单索引功能已禁用");
        }
        reindexService.reindexAll(reindex);
    }

    @Override
    public Page<WaybillIndexVO> search(WaybillIndexFilterDTO filter) {
        return searchService.search(filter);
    }

    @Override
    public Page<WaybillIndexVO> search(WaybillIndexSearchDTO search) {
        return searchService.search(search);
    }

    @Override
    public WaybillIndexScrollVO scroll(WaybillIndexFilterDTO filter) {
        return WaybillIndexTranslator.translate(searchService.scroll(filter));
    }

    @Override
    public WaybillIndexScrollVO scroll(String scrollId) {
        return WaybillIndexTranslator.translate(searchService.scroll(scrollId));
    }

    @Override
    public WaybillIndexSumVO searchSum(WaybillIndexFilterDTO filter) {
        return searchService.searchSum(filter);
    }


    @Override
    public void remove(Long waybillId) {
        indexRepository.deleteById(waybillId);
    }

    @Override
    public WaybillIndexVO getIndexById(Long waybillId) {
        var index = indexRepository.ofId(new WaybillId(waybillId));
        return WaybillIndexTranslator.translate(index);
    }

    @Override
    public JSONObject getWaybillById(Long waybillId) {
        return (JSONObject) JSON.toJSON(sourceFactory.getWaybillById(new WaybillId(waybillId)));
    }

    @Override
    public JSONObject insight(Long waybillId) {
        var indexWaybillId = new WaybillId(waybillId);
        var source = sourceFactory.getSourceById(indexWaybillId);
        var waybill = sourceFactory.getWaybillById(indexWaybillId);
        var newIndex = WaybillIndexConverter.convert(waybill);
        source.put("newIndex", WaybillIndexTranslator.translate(newIndex));
        source.put("oldIndex", this.getIndexById(waybillId));
        return source;
    }

    @Override
    public JSONObject diffs() {
        var diffJson = new JSONObject();
        diffJson.put("diffs", JSON.toJSON(diffService.diffs()));
        diffJson.put("ignores", JSON.toJSON(diffService.ignores()));
        return diffJson;
    }
}
